package games.mapacman.server;

import games.mapacman.common.consts;

import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;
import marauroa.common.crypto.Hash;
import marauroa.common.game.AccountResult;
import marauroa.common.game.CharacterResult;
import marauroa.common.game.IRPZone;
import marauroa.common.game.RPAction;
import marauroa.common.game.RPObject;
import marauroa.common.game.RPObjectInvalidException;
import marauroa.common.game.RPObjectNotFoundException;
import marauroa.common.game.Result;

import marauroa.common.game.RPObject.ID;
import marauroa.server.db.TransactionPool;
import marauroa.server.db.DBTransaction;
import marauroa.server.game.db.DAORegister;
import marauroa.server.game.db.AccountDAO;
import marauroa.server.game.db.CharacterDAO;
import marauroa.server.game.rp.IRPRuleProcessor;
import marauroa.server.game.rp.RPServerManager;
import marauroa.server.game.rp.RPWorld;
import marauroa.server.game.Statistics;

public class MaPacmanRPRuleProcessor implements IRPRuleProcessor
  {
	private static final Logger logger = Logger.getLogger(MaPacmanRPRuleProcessor.class);
    private static MaPacmanRPRuleProcessor instance;
	private RPServerManager rpman;
	private MaPacmanRPWorld world;
	private MaPacmanZone zone;
	private Vector<RPObject> chatChanges;
	private Statistics stats;

	public static IRPRuleProcessor get() {
		if (instance == null) {
			instance = new MaPacmanRPRuleProcessor();
		}
		return instance;
	}

	public void setContext(RPServerManager rpman) {
		stats = Statistics.getStatistics();
		chatChanges = new Vector<RPObject>();	

		// not very fine :( 
		this.world = MaPacmanRPWorld.get();
		this.world.setStats(getStats());
		this.rpman = rpman;
		(new MaPacmanZone("start",this.world)).initialize();
		(new MaPacmanZone("orginal",this.world)).initialize();
		(new MaPacmanZone("map1",this.world)).initialize();
		(new MaPacmanZone("small1",this.world)).initialize();
		(new MaPacmanZone("dungeon1",this.world)).initialize();
		(new MaPacmanZone("dungeon2",this.world)).initialize();
		
	}

	public Statistics getStats()
	{
		return stats;
	}
	
	public boolean checkGameVersion(String game, String version) {
		if (game.equals(consts.GAMENAME) && version.equals(consts.VERSION))
			return true;
		else
		{
			return false;
		}
			
	}

	public boolean onActionAdd(RPObject caster, RPAction action, List<RPAction> actionList) {
		
		return true;
	}

	public void execute(RPObject caster, RPAction action) {
		//System.out.println(action);
		ID id = caster.getID();
		if(action.get("type").equals(consts.CHATMESSAGE)) 
	    {
	      world.get(id).put("text",action.get("content"));
	      world.modify(world.get(id)); 
		  chatChanges.add(world.get(id));
	    }
		else if(action.get("type").equals(consts.CHANGEDIR)) 
	    {
			world.get(id).put("nextdir",action.getInt("content"));
			world.modify(world.get(id));
		}
		
	}

	
	
	synchronized public void beginTurn() {
		
		// check for chat Messages
		for(RPObject object: chatChanges)
		{
			if(object.has("text"))
			{
				object.remove("text");
				world.modify(object);
			}
		}
		chatChanges.clear();
		
		world.beginTurn();
	}

	synchronized public void endTurn() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public synchronized boolean onInit(RPObject object)  
	{
			object.put("zoneid","start");
			if(object.has("text")) object.remove("text");
			object.put("dir",consts.DIR_NONE);
			object.put("power",0);
			object.put("nextdir",consts.DIR_NONE);
			object.put("type", consts.TYPE_PLAYER);  // add by chenbo
			object.put("name", object.get("nick"));
			object.put("x",0);
	        object.put("y",0);
	        object.put("dir",-1);
	        object.put("score",0);

			world.addPlayer(object);
			world.modify(object);
			return true;
	}

	synchronized public boolean onExit(RPObject obj) throws RPObjectNotFoundException {
		world.removePlayer(obj.getID());
		return true;
	}

	synchronized public void onTimeout(RPObject obj) {
		onExit(obj);
	}

    public InputStream getResource(String resource) {
        return null;
	}

	public String getMimeTypeForResource(String resource) {
        return null;
	}

	@Override
	public AccountResult createAccount(String username, String password, String email) {
        TransactionPool transactionPool = TransactionPool.get();
        DBTransaction trans = transactionPool.beginWork();
        AccountDAO accountDAO = DAORegister.get().get(AccountDAO.class);
        try {
           if (accountDAO.hasPlayer(trans, username)) {
              return new AccountResult(Result.FAILED_PLAYER_EXISTS, username);
           }
           accountDAO.addPlayer(trans, username, Hash.hash(password), email);
           transactionPool.commit(trans);
           return new AccountResult(Result.OK_CREATED, username);
        } catch (SQLException e1) {
           transactionPool.rollback(trans);

      return new AccountResult(Result.FAILED_EXCEPTION, username);
	}
	}

    @Override
	public CharacterResult createCharacter(String username, String characterName, RPObject template) {
    TransactionPool transactionPool = TransactionPool.get();
    DBTransaction trans = transactionPool.beginWork();
    CharacterDAO characterDAO = DAORegister.get().get(CharacterDAO.class);
    try {
      if (characterDAO.hasCharacter(trans, username, characterName)) {
        return new CharacterResult(Result.FAILED_CHARACTER_EXISTS, characterName, template);
      }
		  IRPZone zone = world.getRPZone(new IRPZone.ID("start"));
		  RPObject character = new RPObject(template);
		  character.put("nick", characterName);
		  zone.assignRPObjectID(character);
		  characterDAO.addCharacter(trans, username, characterName, character);
		  transactionPool.commit(trans);
		  return new CharacterResult(Result.OK_CREATED, characterName, character);
		} catch (Exception e1) {
		  transactionPool.rollback(trans);
	
		  return new CharacterResult(Result.FAILED_EXCEPTION, characterName, template);
		}
	}


	@Override
	public AccountResult createAccountWithToken(String arg0, String arg1, String arg2) {
		// TODO Auto-generated method stub
		throw new UnsupportedOperationException("Unimplemented method 'createAccountWithToken'");
	}
  }

